package com.waitingresult.common.base.handler;

import cn.hutool.core.util.StrUtil;
import com.waitingresult.common.base.domain.validated.ValidateVo;
import com.waitingresult.common.base.exception.*;
import com.waitingresult.common.base.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.annotation.Priority;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * All right reserved,Designed By WangShuai
 *
 * @author : WangShuai
 * @version : V1.0
 * @ClassName : BaseExceptionHendler
 * @Description : 统一的Controller 异常处理器
 * @date : 2021/9/9 10:57
 */
@RestControllerAdvice
@Priority(1)
@Slf4j
public class BaseExceptionHendler {

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Result<Object> sqlIntegrityConstraintViolationExceptionHandler(SQLIntegrityConstraintViolationException e) {
        return Result.error("SQL可能出现错误.", StrUtil.isEmpty(e.getMessage()) ? "插入数据库失败" : e.getMessage());
    }


    @ExceptionHandler(Exception.class)
    public Result<Object> handleException(Exception e) {
        log.error("发生异常", e);
        return Result.error("发生异常", StrUtil.isEmpty(e.getMessage()) ? "请求异常" : e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    public Result<Object> handleRuntimeException(RuntimeException e) {
        log.error("发生异常", e);
        return Result.error("发生异常", StrUtil.isEmpty(e.getMessage()) ? "请求异常" : e.getMessage());
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<Object> handleNotSupportException(HttpRequestMethodNotSupportedException e) {
        log.debug("发生异常", e);
        return Result.error("发生异常", StrUtil.isEmpty(e.getMessage()) ? "请求异常" : e.getMessage());
    }


    /**
     * =============================Spring-Boot- 参数校验, 异常捕获=================================================================================
     */

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Object> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<ValidateVo> validateVos = getValidateVos(e.getBindingResult());
        Map<String, Object> map = new HashMap<>(1);
        map.put("fieldError", validateVos);
        return Result.error("参数不正确", map);
    }

    /**
     * 使用 @RequestParam 时 hibernate validator 验证异常捕获
     */
    @ExceptionHandler(BindException.class)
    public Result<Object> handleBindException(BindException e) {
        List<ValidateVo> validateVos = getValidateVos(e.getBindingResult());
        Map<String, Object> map = new HashMap<>();
        map.put("fieldError", validateVos);
        return Result.error("参数不正确", map);
    }

    /**
     * hibernate validator 其他验证异常捕获
     */
    @ExceptionHandler({ConstraintViolationException.class, ServletRequestBindingException.class})
    public Result<Object> handleValidationException() {
        Map<String, Object> map = new HashMap<>();
        map.put("fieldError", "参数校验不通过");
        return Result.error("参数不正确", map);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Object> handleHttpMessageNotReadableException() {
        Map<String, Object> map = new HashMap<>();
        map.put("fieldError", "必须要有条件查询,如果没有的话 给一个空对象也要给!,建议可以给分页数据");
        return Result.error("参数不正确", map);
    }

    /**
     * hibernate validator 异常验证VO获取
     */
    private List<ValidateVo> getValidateVos(BindingResult bindingResult) {
        return bindingResult.getFieldErrors()
                .parallelStream()
                .map(error -> new ValidateVo(error.getField(), error.getDefaultMessage()))
                .collect(Collectors.toList());
    }


    /**
     * =========Common自定义公用异常类===============
     */

    @ExceptionHandler(HttpException.class)
    public Result<Object> handleHttpException(HttpException e) {
        return Result.error("发生异常", StrUtil.isEmpty(e.getMessage()) ? "HTTP链接错误" : e.getMessage());
    }

    @ExceptionHandler(CommonException.class)
    public Result<Object> handleCommonException(CommonException e) {
        log.debug("发生异常", e);
        return Result.error("发生异常", StrUtil.isEmpty(e.getMessage()) ? "请求异常" : e.getMessage());
    }

    @ExceptionHandler(TokenException.class)
    public Result<Object> handleTokenException(TokenException e) {
        log.debug("没有权限或未登录", e);
        return Result.needLogin(StrUtil.isEmpty(e.getMessage()) ? "没有权限或未登录" : e.getMessage());
    }

    @ExceptionHandler(ValidateException.class)
    public Result<Object> handleValidateException(ValidateException e) {
        log.debug("验证异常", e);
        return Result.needLogin(StrUtil.isEmpty(e.getMessage()) ? "验证异常" : e.getMessage());
    }

    @ExceptionHandler(LockTimeoutException.class)
    public Result<Object> handleLockTimeoutException(LockTimeoutException e) {
        log.debug("锁超时异常", e);
        return Result.needLogin(StrUtil.isEmpty(e.getMessage()) ? "锁超时异常" : e.getMessage());
    }
}
